package com.virgil.core.config;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.virgil.core.utils.IpUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * @author virgil
 * @since 2018-07-22
 *        <p>
 *        	日志切面
 *        </p>
 */
@Aspect
@Slf4j
public class RequestLogAspect {

	private LogProperties logProperties;

	public RequestLogAspect(LogProperties logProperties) {
		this.logProperties = logProperties;
	}

	/**
	 * 定义切点
	 */
	@Pointcut("@annotation(com.virgil.core.annotation.ApiLog)")
	public void requestServer() {

	}

	/**
	 * 
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@Around("requestServer()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		StringBuffer str = new StringBuffer();
		long beginTime = System.currentTimeMillis();
		// 获取请求信息
		ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = sra.getRequest();

		// 获取代理地址、请求地址、请求类名、方法名
		if (logProperties.getIp()) {
			String remoteAddress = IpUtils.getIpAddr(request);
			str.append(" IP信息->【").append(remoteAddress).append("】");
		}
		if (logProperties.getUrl()) {
			String requestURI = request.getRequestURI();
			str.append(" URI信息->【").append(requestURI).append("】");
		}
		if (logProperties.getClazz()) {
			String clazzName = pjp.getTarget().getClass().getSimpleName();
			str.append(" 请求映射控制类->【").append(clazzName).append("】");
		}
		if (logProperties.getMethod()) {
			String methodName = pjp.getSignature().getName();
			str.append(" 请求方法->【").append(methodName).append("】");
		}
		if (logProperties.getParams()) {
			StringBuilder sb = new StringBuilder();
			// 获取请求参数：
			MethodSignature ms = (MethodSignature) pjp.getSignature();
			String[] parameterNames = ms.getParameterNames();
			// 获取请求参数值
			Object[] parameterValues = pjp.getArgs();
			// 组合请求参数，进行日志打印
			if (parameterNames != null && parameterNames.length > 0) {
				for (int i = 0; i < parameterNames.length; i++) {
					if ("file".equals(parameterNames[i])) {
						break;
					}
					sb.append("[").append(parameterNames[i]).append("=").append(JSON.toJSONString(parameterValues[i]))
							.append("]");
				}
			}
			str.append(" 请求参数列表->【").append(sb.toString()).append("】");
		}

		Object result = null;
		try {
			result = pjp.proceed();
			if (logProperties.getTime()) {
				// 记录请求完成执行时间
				long use = System.currentTimeMillis() - beginTime;
				str.insert(0, "ms】").insert(0, use).insert(0, " 耗时->【");
			}
		} catch (Throwable throwable) {
			// 请求操作失败,记录错误日志
			log.error("Fail ~ {}", str.toString());
			throw throwable;
		}
		// 请求操作成功
		if (logProperties.getResult()) {
			String resultJosnString = (result == null) ? "null" : JSON.toJSONString(result);
			str.append(" 返回值->【").append(resultJosnString).append("】");
		}
		// 记录日志
		log.info("Success ~ {}", str.toString());
		return result;
	}
}
